﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using ZillowApiClient.Data.Model;

namespace ZillowApiClient.Data
{
    public class ZillowClient
    {
        public HttpClientHandler Handler { get; set; }

        public string ZillowApiId { get; set; }

        public TimeSpan Timeout { get; set; }

        public ZillowClient(string zillowApiId, int timeout)
        {
            ZillowApiId = zillowApiId;
            Timeout = TimeSpan.FromSeconds(timeout);
            Handler = new HttpClientHandler() { AllowAutoRedirect = true };
        }

        public async Task<List<result>> GetAsync(string address, string citystatezip)
        {
            using (var client = new HttpClient(Handler))
            {
                client.Timeout = Timeout;
                var result = await client.GetAsync(new Uri("http://www.zillow.com/webservice/GetSearchResults.htm?zws-id=" + ZillowApiId + "&address=" + address + "&citystatezip=" + citystatezip));
                var message = result.Content.ReadAsStringAsync().Result;
                var doc = new XmlDocument();
                doc.LoadXml(message);
                XmlElement root = doc.DocumentElement;
                var messageXml = "<message>" + root.GetElementsByTagName("message")[0].InnerXml + "</message>";
                var messageCode = LoadFromXMLString<message>(messageXml);
                if (messageCode.code != 0)
                {
                    var errorString = ResolveError(messageCode);
                    Console.WriteLine($"{errorString} : {messageCode.text} ");
                    throw new HttpRequestException(ResolveError(messageCode));
                }
                var results = LoadFromXMLString<searchresults>("<searchresults><results>" + root.GetElementsByTagName("results")[0].InnerXml + "</results></searchresults>");
                return results.results;
            }
        }

        public string ToXML()
        {
            var stringwriter = new System.IO.StringWriter();
            var serializer = new XmlSerializer(this.GetType());
            serializer.Serialize(stringwriter, this);
            return stringwriter.ToString();
        }

        public static T LoadFromXMLString<T>(string xmlText)
            where T : class
        {
            var stringReader = new System.IO.StringReader(xmlText);
            var serializer = new XmlSerializer(typeof(T));
            return serializer.Deserialize(stringReader) as T;
        }

        public string ResolveError(message messageCode)
        {
            switch (messageCode.code)
            {
                case 0:
                    return "Request successfully processed.";

                case 1:
                    return
                        "Service error-there was a server-side error while processing the request\r\n Suggestion:Check to see if your url is properly formed: delimiters, character cases, etc..";
                case 2:
                    return
                        "The specified ZWSID parameter was invalid or not specified in the request\r\n Suggestion:Check if you have provided a ZWSID in your API call. If yes, check if the ZWSID is keyed in correctly. If it still doesn't work, contact Zillow to get help on fixing your ZWSID..";
                case 3:
                    return
                        "Web services are currently unavailable\r\n Suggestion:The Zillow Web Service is currently not available. Please come back later and try again..";
                case 4:
                    return
                        "The API call is currently unavailable\r\n Suggestion:The Zillow Web Service is currently not available. Please come back later and try again..";
                case 500:
                    return
                        "Invalid or missing address parameter\r\n Suggestion:Check if the input address matches the format specified in the input parameters table. When inputting a city name, include the state too. A city name alone will not result in a valid address..";
                case 501:
                    return "Invalid or missing citystatezip parameter\r\n Suggestion:Same as error 500..";

                case 502:
                    return
                        "No results found\r\n Suggestion:Sorry, the address you provided is not found in Zillow's property database.";
                case 503:
                    return
                        "Failed to resolve city, state or ZIP code\r\n Suggestion:Please check to see if the city/state you entered is valid. If you provided a ZIP code, check to see if it is valid.";
                case 504:
                    return
                        "No coverage for specified area\r\n Suggestion:The specified area is not covered by the Zillow property database. To see our property coverage tables, click here.";
                case 505:
                    return
                        "Timeout\r\n Suggestion:Your request timed out. The server could be busy or unavailable. Try again later..";
                case 506:
                    return "address string too long\r\n Suggestion:If address is valid, try using abbreviations.";

                case 507:
                    return "No exact match found.\r\n Suggestion:Verify that the given address is correct.";

                case 7:
                    return "Zillow API account has exceeded maximum of 1000 calls today.";

                default:
                    return ($"{messageCode.text}");
            }
        }
    }
}